Micron Document
🎖️GitЯра🎖️

Commit 1c0dc486e2b68c578d793caebc51d46bb1af8be6


Parents : ef9c0dc
Author : Mac DeCourcy <49794076+mdecourcy@users.noreply.github.com>
Signature : Signature validation error
Date : 2025-11-28T09:38:30-08:00
Committer : GitHub <noreply@github.com>
Date : 2025-11-28T17:38:30Z

fix: node search by keeping denormalized name columns up to date and backfilling existing nodes (#3839)

Changes
Diff

diff --git a/core/data/src/main/kotlin/org/meshtastic/core/data/datasource/NodeInfoWriteDataSource.kt b/core/data/src/main/kotlin/org/meshtastic/core/data/datasource/NodeInfoWriteDataSource.kt
index b837ef7273..fb0d8fe0ed 100644
--- a/core/data/src/main/kotlin/org/meshtastic/core/data/datasource/NodeInfoWriteDataSource.kt
+++ b/core/data/src/main/kotlin/org/meshtastic/core/data/datasource/NodeInfoWriteDataSource.kt
@@ -37,4 +37,6 @@ interface NodeInfoWriteDataSource {
suspend fun upsert(metadata: MetadataEntity)
suspend fun setNodeNotes(num: Int, notes: String)
+
+ suspend fun backfillDenormalizedNames()
}

diff --git a/core/data/src/main/kotlin/org/meshtastic/core/data/datasource/SwitchingNodeInfoWriteDataSource.kt b/core/data/src/main/kotlin/org/meshtastic/core/data/datasource/SwitchingNodeInfoWriteDataSource.kt
index ee24ee73b6..872b47ae6d 100644
--- a/core/data/src/main/kotlin/org/meshtastic/core/data/datasource/SwitchingNodeInfoWriteDataSource.kt
+++ b/core/data/src/main/kotlin/org/meshtastic/core/data/datasource/SwitchingNodeInfoWriteDataSource.kt
@@ -57,4 +57,7 @@ constructor(
override suspend fun setNodeNotes(num: Int, notes: String) =
withContext(dispatchers.io) { dbManager.withDb { it.nodeInfoDao().setNodeNotes(num, notes) } }
+
+ override suspend fun backfillDenormalizedNames() =
+ withContext(dispatchers.io) { dbManager.withDb { it.nodeInfoDao().backfillDenormalizedNames() } }
}

diff --git a/core/data/src/main/kotlin/org/meshtastic/core/data/repository/NodeRepository.kt b/core/data/src/main/kotlin/org/meshtastic/core/data/repository/NodeRepository.kt
index 3f767ef887..b245566ecd 100644
--- a/core/data/src/main/kotlin/org/meshtastic/core/data/repository/NodeRepository.kt
+++ b/core/data/src/main/kotlin/org/meshtastic/core/data/repository/NodeRepository.kt
@@ -54,6 +54,13 @@ constructor(
private val nodeInfoWriteDataSource: NodeInfoWriteDataSource,
private val dispatchers: CoroutineDispatchers,
) {
+ init {
+ // Backfill denormalized name columns for existing nodes on startup
+ processLifecycle.coroutineScope.launchWhenCreated {
+ withContext(dispatchers.io) { nodeInfoWriteDataSource.backfillDenormalizedNames() }
+ }
+ }
+
// hardware info about our local device (can be null)
val myNodeInfo: StateFlow<MyNodeEntity?> =
nodeInfoReadDataSource

diff --git a/core/database/src/main/kotlin/org/meshtastic/core/database/dao/NodeInfoDao.kt b/core/database/src/main/kotlin/org/meshtastic/core/database/dao/NodeInfoDao.kt
index e6c99f7dfd..c0edaa57c3 100644
--- a/core/database/src/main/kotlin/org/meshtastic/core/database/dao/NodeInfoDao.kt
+++ b/core/database/src/main/kotlin/org/meshtastic/core/database/dao/NodeInfoDao.kt
@@ -30,6 +30,7 @@ import org.meshtastic.core.database.entity.MetadataEntity
import org.meshtastic.core.database.entity.MyNodeEntity
import org.meshtastic.core.database.entity.NodeEntity
import org.meshtastic.core.database.entity.NodeWithRelations
+import org.meshtastic.proto.MeshProtos
@Suppress("TooManyFunctions")
@Dao
@@ -49,6 +50,13 @@ interface NodeInfoDao {
// and to support lazy migration.
incomingNode.publicKey = incomingNode.user.publicKey
+ // Populate denormalized name columns from the User protobuf for search functionality
+ // Only populate if the user is not a placeholder (hwModel != UNSET)
+ if (incomingNode.user.hwModel != MeshProtos.HardwareModel.UNSET) {
+ incomingNode.longName = incomingNode.user.longName
+ incomingNode.shortName = incomingNode.user.shortName
+ }
+
val existingNodeEntity = getNodeByNum(incomingNode.num)?.node
return if (existingNodeEntity == null) {
@@ -240,4 +248,27 @@ interface NodeInfoDao {
setMyNodeInfo(mi)
putAll(nodes.map { getVerifiedNodeForUpsert(it) })
}
+
+ /**
+ * Backfills longName and shortName columns from the user protobuf for nodes where these columns are NULL. This
+ * ensures search functionality works for all nodes. Skips placeholder/default users (hwModel == UNSET).
+ */
+ @Transaction
+ fun backfillDenormalizedNames() {
+ val nodes = getAllNodesSnapshot()
+ val nodesToUpdate =
+ nodes
+ .filter { node ->
+ // Only backfill if columns are NULL AND the user is not a placeholder (hwModel != UNSET)
+ (node.longName == null || node.shortName == null) &&
+ node.user.hwModel != MeshProtos.HardwareModel.UNSET
+ }
+ .map { node -> node.copy(longName = node.user.longName, shortName = node.user.shortName) }
+ if (nodesToUpdate.isNotEmpty()) {
+ putAll(nodesToUpdate)
+ }
+ }
+
+ @Query("SELECT * FROM nodes")
+ fun getAllNodesSnapshot(): List<NodeEntity>
}

diff --git a/feature/node/src/main/kotlin/org/meshtastic/feature/node/list/NodeListViewModel.kt b/feature/node/src/main/kotlin/org/meshtastic/feature/node/list/NodeListViewModel.kt
index b0f85cb86a..497bed25da 100644
--- a/feature/node/src/main/kotlin/org/meshtastic/feature/node/list/NodeListViewModel.kt
+++ b/feature/node/src/main/kotlin/org/meshtastic/feature/node/list/NodeListViewModel.kt
@@ -108,7 +108,7 @@ constructor(
)
.map { list ->
list
- .filter { it.isIgnored == filter.showIgnored }
+ .filter { filter.showIgnored || !it.isIgnored }
.filter { node ->
if (filter.excludeInfrastructure) {
val role = node.user.role

Served by rngit 1.4.2 - Generated in 0.1s